package besta.moon.engine.table;

import java.io.*;
import java.nio.channels.FileChannel;
import java.sql.*;

import besta.moon.MoonException;
import besta.moon.MoonConnection;
import besta.moon.metadata.MoonResultSetMetaData;
import besta.moon.MoonCode;
import besta.moon.sql.Expression;
import besta.moon.sql.datatype.Identity;
import besta.moon.sql.expression.ExpressionValue;
import besta.moon.sql.parser.SQLTokenizer;

public class Column implements Cloneable {


    private Expression defaultValue = Expression.NULL; 
    private String defaultDefinition; 
    private String name;
    private boolean identity;
    private boolean caseSensitive;
    private boolean nullable = true;
    private int scale;
    private int precision;
    private int dataType;
    private Identity counter;

    public void setName(String name) {
        this.name = name;
    }

    public void setDefaultValue(Expression defaultValue,
            String defaultDefinition) {
        this.defaultValue = defaultValue;
        this.defaultDefinition = defaultDefinition;
    }

    public Expression getDefaultValue(MoonConnection con) throws SQLException {
        if (identity) {
            counter.createNextValue(con);
        }
        return defaultValue;
    }

    public String getDefaultDefinition() {
        return defaultDefinition;
    }

    public String getName() {
        return name;
    }

    public boolean isAutoIncrement() {
        return identity;
    }

    public void setAutoIncrement(boolean identity) {
        this.identity = identity;
    }

    public int initAutoIncrement(FileChannel raFile, long filePos)
            throws IOException {
        if (identity) {
            counter = new Identity(raFile, filePos);
            defaultValue = new ExpressionValue(counter, SQLTokenizer.BIGINT);
        }
        return 8;
    }

    public void setNewAutoIncrementValue(Expression obj) throws Exception {
        if (identity) {
            counter.setNextValue(obj);
        }
    }

    public boolean isCaseSensitive() {
        return caseSensitive;
    }

    public void setNullable(boolean nullable) {
        this.nullable = nullable;
    }

    public boolean isNullable() {
        return nullable;
    }

    public void setDataType(int dataType) {
        this.dataType = dataType;
    }

    public int getDataType() {
        return dataType;
    }

    public int getDisplaySize() {
        return MoonResultSetMetaData.getDisplaySize(dataType, precision, scale);
    }

    public void setScale(int scale) {
        this.scale = scale;
    }

    public int getScale() {
        return switch (dataType) {
            case SQLTokenizer.DECIMAL, SQLTokenizer.NUMERIC -> scale;
            default -> Expression.getScale(dataType);
        };
    }

    public void setPrecision(int precision) throws SQLException {
        if (precision < 0) {
            throw MoonException.create(MoonCode.COL_INVALID_SIZE,
                    new Object[]{precision, name});
        }
        this.precision = precision;
    }

    public int getPrecision() {
        return MoonResultSetMetaData.getDataTypePrecision(dataType, precision);
    }

    public int getColumnSize() {
        if (MoonResultSetMetaData.isNumberDataType(dataType)) {
            return getPrecision();
        } else {
            return getDisplaySize();
        }
    }

    public int getFlag() {
        return (identity ? 1 : 0) | (caseSensitive ? 2 : 0)
                | (nullable ? 4 : 0);
    }

    public void setFlag(int flag) {
        identity = (flag & 1) > 0;
        caseSensitive = (flag & 2) > 0;
        nullable = (flag & 4) > 0;
    }

    public Column copy() {
        try {
            return (Column) clone();
        } catch (CloneNotSupportedException e) {
            return null;
        }

    }
}
